#include "stdafx.h"
#include "DownloadManager.h"
#include <QDebug>
#include <QFileInfo>
#include <QDir>

DownloadManager::DownloadManager(QObject* parent)
    : QObject(parent)
    , m_manager(new QNetworkAccessManager(this))
    , m_reply(nullptr)
    , m_file(nullptr)
    , m_speedTimer(new QTimer(this))
    , m_totalSize(0)
    , m_downloadedSize(0)
    , m_lastDownloadedSize(0)
    , m_currentSpeed(0)
    , m_state(Idle)
{
    connect(m_speedTimer, &QTimer::timeout, this, &DownloadManager::updateSpeed);
}

DownloadManager::~DownloadManager()
{
    cancelDownload();
}

void DownloadManager::startDownload(const QString& url, const QString& filePath)
{
    if (m_state == Downloading) {
        emit errorOccurred("已有下载任务正在进行");
        return;
    }

    m_url = url;
    m_filePath = filePath;

    // 验证URL
    QUrl qurl(url);
    if (!qurl.isValid() || qurl.scheme().isEmpty()) {
        m_errorMessage = "无效的URL地址: " + url;
        setState(Error);
        emit errorOccurred(m_errorMessage);
        return;
    }

    // 检查并创建目录
    QFileInfo fileInfo(filePath);
    QDir dir = fileInfo.absoluteDir();
    if (!dir.exists() && !dir.mkpath(".")) {
        m_errorMessage = "无法创建目录: " + dir.absolutePath();
        setState(Error);
        emit errorOccurred(m_errorMessage);
        return;
    }

    // 打开文件
    if (!openFileForWriting()) {
        m_errorMessage = "无法创建文件: " + filePath;
        setState(Error);
        emit errorOccurred(m_errorMessage);
        return;
    }

    QNetworkRequest request(qurl);
    // request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
  //   request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
   // request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true);

     // 支持断点续传
    if (fileInfo.exists() && fileInfo.size() > 0) {
        qint64 existingSize = fileInfo.size();
        request.setRawHeader("Range", QString("bytes=%1-").arg(existingSize).toUtf8());
        m_downloadedSize = existingSize;
        qDebug() << "断点续传，已下载:" << m_downloadedSize << "字节";
    }
    else {
        m_downloadedSize = 0;
    }

    m_lastDownloadedSize = m_downloadedSize;

    // 开始下载
    m_reply = m_manager->get(request);

    // 连接信号槽 - 使用新式Qt5连接语法
    connect(m_reply, &QNetworkReply::readyRead, this, &DownloadManager::onReadyRead);
    connect(m_reply, &QNetworkReply::downloadProgress, this, &DownloadManager::onDownloadProgress);
    connect(m_reply, &QNetworkReply::finished, this, &DownloadManager::onFinished);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
    connect(m_reply, &QNetworkReply::errorOccurred, this, &DownloadManager::onErrorOccurred);
#else
    connect(m_reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &DownloadManager::onErrorOccurred);
#endif

    // 启动速度计时器
    m_downloadTimer.start();
    m_speedTimer->start(1000);

    setState(Downloading);
    qDebug() << "开始下载:" << url << "到:" << filePath;
}

void DownloadManager::pauseDownload()
{
    if (m_state == Downloading && m_reply) {
        // 先停止定时器
        m_speedTimer->stop();

        // 中止网络请求
        m_reply->abort();

        // 刷新文件
        if (m_file && m_file->isOpen()) {
            m_file->flush();
        }

        setState(Paused);
        qDebug() << "下载已暂停";
    }
}

void DownloadManager::resumeDownload()
{
    if (m_state == Paused) {
        qDebug() << "恢复下载";
        startDownload(m_url, m_filePath);
    }
}

void DownloadManager::cancelDownload()
{
    // 停止定时器
    m_speedTimer->stop();

    // 清理网络回复
    if (m_reply) {
        m_reply->abort();
        m_reply->deleteLater();
        m_reply = nullptr;
    }

    // 清理文件
    if (m_file) {
        if (m_file->isOpen()) {
            m_file->close();
        }

        // 只有在下载未完成时才删除文件
        if (m_state != Completed && m_file->exists()) {
            m_file->remove();
        }

        m_file->deleteLater();
        m_file = nullptr;
    }

    if (m_state != Completed) {
        setState(Idle);
    }

    qDebug() << "下载已取消";
}

double DownloadManager::getProgress() const
{
    if (m_totalSize > 0) {
        return (static_cast<double>(m_downloadedSize) / m_totalSize) * 100.0;
    }
    return 0.0;
}

QString DownloadManager::getSpeed() const
{
    return formatSpeed(static_cast<qint64>(m_currentSpeed));
}

void DownloadManager::onReadyRead()
{
    if (m_reply && m_file && m_file->isOpen()) {
        QByteArray data = m_reply->readAll();
        qint64 bytesWritten = m_file->write(data);

        if (bytesWritten == -1) {
            m_errorMessage = "文件写入错误: " + m_file->errorString();
            setState(Error);
            emit errorOccurred(m_errorMessage);
            cancelDownload();
            return;
        }

        if (bytesWritten != data.size()) {
            m_errorMessage = QString("文件写入不完整: %1/%2 字节").arg(bytesWritten).arg(data.size());
            setState(Error);
            emit errorOccurred(m_errorMessage);
            cancelDownload();
        }
    }
}

void DownloadManager::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    // 对于断点续传，需要调整接收到的字节数
    qint64 actualBytesReceived = bytesReceived;
    if (m_downloadedSize > 0) {
        // 如果是续传，bytesReceived是从续传点开始的进度
        actualBytesReceived = m_downloadedSize + bytesReceived;
    }

    m_downloadedSize = actualBytesReceived;
    m_totalSize = bytesTotal > 0 ? bytesTotal : 0;

    // 如果是续传且服务器返回了正确的内容范围，调整总大小
    if (m_downloadedSize > 0 && bytesTotal > 0) {
        m_totalSize = m_downloadedSize + bytesTotal;
    }

    double percentage = getProgress();
    emit progressChanged(percentage, m_downloadedSize, m_totalSize);

    qDebug() << "下载进度:" << QString::number(percentage, 'f', 1) << "%"
        << m_downloadedSize << "/" << m_totalSize << "bytes";
}

void DownloadManager::onFinished()
{
    m_speedTimer->stop();

    if (!m_reply) {
        return;
    }

    bool success = false;
    QString message;

    // 检查回复状态码
    QVariant statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    int httpStatus = statusCode.toInt();

    if (m_reply->error() == QNetworkReply::NoError) {
        // 写入剩余数据
        if (m_file && m_file->isOpen()) {
            QByteArray remainingData = m_reply->readAll();
            if (!remainingData.isEmpty()) {
                qint64 written = m_file->write(remainingData);
                if (written != remainingData.size()) {
                    success = false;
                    message = "文件写入不完整";
                }
                else {
                    success = true;
                    message = "下载完成";
                }
            }
            else {
                success = true;
                message = "下载完成";
            }
            m_file->close();
        }

        if (success) {
            setState(Completed);
            qDebug() << "下载成功:" << m_filePath << "HTTP状态:" << httpStatus;
        }
    }
    else if (m_state == Paused) {
        // 暂停状态，不视为错误
        success = false;
        message = "下载已暂停";
        qDebug() << "下载暂停";

        // 保持Paused状态，不清理资源以便恢复
        m_reply->deleteLater();
        m_reply = nullptr;
        emit finished(success, message);
        return;
    }
    else {
        if (m_file && m_file->isOpen()) {
            m_file->close();
        }
        success = false;
        message = QString("下载失败(%1): %2").arg(httpStatus).arg(m_reply->errorString());
        setState(Error);
        m_errorMessage = message;
        qDebug() << "下载失败:" << message;
    }

    // 清理资源
    if (m_reply) {
        m_reply->deleteLater();
        m_reply = nullptr;
    }

    if (m_file) {
        if (success) {
            // 下载成功，清理文件指针但不删除文件
            m_file->deleteLater();
            m_file = nullptr;
        }
        else if (m_state != Paused) {
            // 下载失败且不是暂停状态，删除不完整文件
            if (m_file->exists()) {
                m_file->remove();
            }
            m_file->deleteLater();
            m_file = nullptr;
        }
    }

    emit finished(success, message);
}

void DownloadManager::onErrorOccurred(QNetworkReply::NetworkError code)
{
    Q_UNUSED(code)

        // 如果是暂停操作导致的错误，忽略
        if (m_state == Paused) {
            return;
        }

    if (m_reply) {
        m_errorMessage = m_reply->errorString();
        setState(Error);
        emit errorOccurred(m_errorMessage);
        qDebug() << "网络错误:" << m_errorMessage;
    }
}

void DownloadManager::updateSpeed()
{
    if (m_state == Downloading) {
        qint64 currentBytes = m_downloadedSize;
        qint64 bytesDiff = currentBytes - m_lastDownloadedSize;

        if (m_downloadTimer.isValid()) {
            qint64 elapsed = m_downloadTimer.elapsed();
            if (elapsed > 0) {
                m_currentSpeed = bytesDiff * 1000.0 / elapsed; // 转换为每秒字节数
            }
        }

        m_lastDownloadedSize = currentBytes;
        m_downloadTimer.restart();

        emit speedUpdated(getSpeed());
    }
}

void DownloadManager::setState(DownloadState state)
{
    if (m_state != state) {
        m_state = state;
        emit stateChanged(state);
        qDebug() << "状态改变:" << state;
    }
}

void DownloadManager::reset()
{
    cancelDownload();
    m_totalSize = 0;
    m_downloadedSize = 0;
    m_lastDownloadedSize = 0;
    m_currentSpeed = 0;
    m_errorMessage.clear();
    m_url.clear();
    m_filePath.clear();
    setState(Idle);
}

bool DownloadManager::openFileForWriting()
{
    // 清理现有文件对象
    if (m_file) {
        if (m_file->isOpen()) {
            m_file->close();
        }
        m_file->deleteLater();
        m_file = nullptr;
    }

    m_file = new QFile(m_filePath);

    QFileInfo fileInfo(m_filePath);
    bool isResume = fileInfo.exists() && fileInfo.size() > 0;

    // 打开文件
    if (isResume) {
        // 续传：以追加模式打开
        if (!m_file->open(QIODevice::WriteOnly | QIODevice::Append)) {
            m_errorMessage = "无法以追加模式打开文件: " + m_file->errorString();
            return false;
        }
    }
    else {
        // 新下载：创建新文件
        if (!m_file->open(QIODevice::WriteOnly)) {
            m_errorMessage = "无法创建文件: " + m_file->errorString();
            return false;
        }
    }

    return true;
}

QString DownloadManager::formatSpeed(qint64 bytesPerSecond) const
{
    if (bytesPerSecond < 1024) {
        return QString("%1 B/s").arg(bytesPerSecond);
    }
    else if (bytesPerSecond < 1024 * 1024) {
        return QString("%1 KB/s").arg(bytesPerSecond / 1024.0, 0, 'f', 1);
    }
    else {
        return QString("%1 MB/s").arg(bytesPerSecond / (1024.0 * 1024.0), 0, 'f', 1);
    }
}

QString DownloadManager::formatSize(qint64 bytes) const
{
    if (bytes < 1024) {
        return QString("%1 B").arg(bytes);
    }
    else if (bytes < 1024 * 1024) {
        return QString("%1 KB").arg(bytes / 1024.0, 0, 'f', 1);
    }
    else if (bytes < 1024 * 1024 * 1024) {
        return QString("%1 MB").arg(bytes / (1024.0 * 1024.0), 0, 'f', 1);
    }
    else {
        return QString("%1 GB").arg(bytes / (1024.0 * 1024.0 * 1024.0), 0, 'f', 1);
    }
}